home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / plot2d.c < prev    next >
C/C++ Source or Header  |  1998-12-09  |  44KB  |  1,396 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: plot2d.c,v 1.53 1998/06/18 14:55:14 ddenholm Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - plot2d.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37. #include "plot.h"
  38. #include "setshow.h"
  39. #include "fit.h"
  40. #include "binary.h"
  41.  
  42. #ifndef _Windows
  43. # include "help.h"
  44. #endif
  45.  
  46. #ifndef STDOUT
  47. #define STDOUT 1
  48. #endif
  49.  
  50. /* static prototypes */
  51.  
  52. void plotrequest __PROTO((void));
  53. void plot3drequest __PROTO((void));
  54. void define __PROTO((void));
  55. static void get_data __PROTO((struct curve_points * this_plot));
  56. static void store2d_point __PROTO((struct curve_points * this_plot, int i, double x, double y, double xlow, double xhigh, double ylow, double yhigh, double width));
  57. static void print_table __PROTO((struct curve_points * first_plot, int plot_num));
  58. static void eval_plots __PROTO((void));
  59. static void parametric_fixup __PROTO((struct curve_points * start_plot, int *plot_num));
  60.  
  61.  
  62. /* the curves/surfaces of the plot */
  63. struct curve_points *first_plot = NULL;
  64. static struct udft_entry plot_func;
  65. extern struct udft_entry *dummy_func;
  66.  
  67. /* jev -- for passing data thru user-defined function */
  68. /* Needed by datafile.c */
  69. struct udft_entry ydata_func;
  70.  
  71. extern int datatype[];
  72. extern char timefmt[];
  73.  
  74. extern TBOOLEAN is_3d_plot;
  75. extern int plot_token;
  76.  
  77. /* in order to support multiple axes, and to
  78.  * simplify ranging in parametric plots, we use
  79.  * arrays to store some things.
  80.  * Elements are z = 0, y1 = 1, x1 = 2, [z2 =4 ], y2 = 5, x2 = 6
  81.  * these are given symbolic names in plot.h
  82.  */
  83.  
  84. /* Were declared in command.c */
  85. double min_array[AXIS_ARRAY_SIZE], max_array[AXIS_ARRAY_SIZE];
  86. int auto_array[AXIS_ARRAY_SIZE];
  87. TBOOLEAN log_array[AXIS_ARRAY_SIZE];
  88. double base_array[AXIS_ARRAY_SIZE];
  89. double log_base_array[AXIS_ARRAY_SIZE];
  90.  
  91. /* Deleted from setshow.h and renamed */
  92. extern FILE *gpoutfile;
  93.  
  94. /* if user specifies [10:-10] we use [-10:10] internally, and swap at end */
  95. int reverse_range[AXIS_ARRAY_SIZE];
  96.  
  97. /* info from datafile module */
  98. extern int df_datum;
  99. extern int df_line_number;
  100. extern int df_no_use_specs;
  101. extern int df_eof;
  102. extern int df_timecol[];
  103. extern TBOOLEAN df_binary;
  104.  
  105. #define Inc_c_token if (++c_token >= num_tokens)    \
  106.                         int_error ("Syntax error", c_token);
  107.  
  108.  
  109. /*
  110.  * IMHO, code is getting too cluttered with repeated chunks of
  111.  * code. Some macros to simplify, I hope.
  112.  *
  113.  * do { } while(0) is comp.lang.c recommendation for complex macros
  114.  * also means that break can be specified as an action, and it will
  115.  * 
  116.  */
  117.  
  118. /*  copy scalar data to arrays
  119.  * optimiser should optimise infinite away
  120.  * dont know we have to support ranges [10:-10] - lets reverse
  121.  * it for now, then fix it at the end.
  122.  */
  123. #define INIT_ARRAYS(axis, min, max, auto, is_log, base, log_base, infinite) \
  124. do{auto_array[axis] = auto; \
  125.    min_array[axis] = (infinite && (auto&1)) ? VERYLARGE : min; \
  126.    max_array[axis] = (infinite && (auto&2)) ? -VERYLARGE : max; \
  127.    log_array[axis] = is_log; base_array[axis] = base; log_base_array[axis] = log_base;\
  128. }while(0)
  129. /* handle reversed ranges */
  130. #define CHECK_REVERSE(axis) \
  131. do{\
  132.  if (auto_array[axis] == 0 && max_array[axis] < min_array[axis]) {\
  133.   double temp = min_array[axis]; min_array[axis] = max_array[axis]; max_array[axis] = temp;\
  134.   reverse_range[axis] = 1; \
  135.  } else reverse_range[axis] = (range_flags[axis]&RANGE_REVERSE); \
  136. }while(0)
  137.  
  138.  
  139. /* get optional [min:max] */
  140. #define LOAD_RANGE(axis) \
  141. do {\
  142.  if (equals(c_token, "[")) { \
  143.   c_token++; \
  144.   auto_array[axis] = load_range(axis,&min_array[axis], &max_array[axis], auto_array[axis]);\
  145.   if (!equals(c_token, "]"))\
  146.    int_error("']' expected", c_token);\
  147.   c_token++;\
  148.  }\
  149. } while (0)
  150.  
  151.  
  152. /* store VALUE or log(VALUE) in STORE, set TYPE as appropriate
  153.  * Do OUT_ACTION or UNDEF_ACTION as appropriate
  154.  * adjust range provided type is INRANGE (ie dont adjust y if x is outrange
  155.  * VALUE must not be same as STORE
  156.  */
  157.  
  158. #define STORE_WITH_LOG_AND_FIXUP_RANGE(STORE, VALUE, TYPE, AXIS, OUT_ACTION, UNDEF_ACTION)\
  159. do { if (log_array[AXIS]) { if (VALUE<0.0) {TYPE = UNDEFINED; UNDEF_ACTION; break;} \
  160.               else if (VALUE == 0.0){STORE = -VERYLARGE; TYPE = OUTRANGE; OUT_ACTION; break;} \
  161.               else { STORE = log(VALUE)/log_base_array[AXIS]; } \
  162.      } else STORE = VALUE; \
  163.      if (TYPE != INRANGE) break;  /* dont set y range if x is outrange, for example */ \
  164.      if ( VALUE<min_array[AXIS] ) { \
  165.       if (auto_array[AXIS] & 1) min_array[AXIS] = VALUE; else { TYPE = OUTRANGE; OUT_ACTION; break; }  \
  166.      } \
  167.      if ( VALUE>max_array[AXIS] ) { \
  168.       if (auto_array[AXIS] & 2) max_array[AXIS] = VALUE; else { TYPE = OUTRANGE; OUT_ACTION; }   \
  169.      } \
  170. } while(0)
  171.  
  172. /* use this instead empty macro arguments to work around NeXT cpp bug */
  173. /* if this fails on any system, we might use ((void)0) */
  174. #define NOOP            /* */
  175.  
  176. /* check range and take logs of min and max if logscale
  177.  * this also restores min and max for ranges like [10:-10]
  178.  */
  179. #ifdef HAVE_STRINGIZE
  180. # define LOG_MSG(x) #x " range must be greater than 0 for log scale!"
  181. #else
  182. # define LOG_MSG(x) "x range must be greater than 0 for log scale!"
  183. #endif
  184.  
  185. #define FIXUP_RANGE_FOR_LOG(AXIS, WHICH) \
  186. do { if (reverse_range[AXIS]) { \
  187.       double temp = min_array[AXIS]; \
  188.       min_array[AXIS] = max_array[AXIS]; \
  189.       max_array[AXIS] = temp; \
  190.      }\
  191.      if (log_array[AXIS]) { \
  192.       if (min_array[AXIS] <= 0.0 || max_array[AXIS] <= 0.0) \
  193.        int_error(LOG_MSG(WHICH), NO_CARET); \
  194.       min_array[AXIS] = log(min_array[AXIS])/log_base_array[AXIS]; \
  195.       max_array[AXIS] = log(max_array[AXIS])/log_base_array[AXIS];  \
  196.    } \
  197. } while(0)
  198.  
  199.  
  200.  
  201. void plotrequest()
  202. /*
  203.  * In the parametric case we can say plot [a= -4:4] [-2:2] [-1:1] sin(a),a**2
  204.  * while in the non-parametric case we would say only plot [b= -2:2] [-1:1]
  205.  * sin(b)
  206.  */
  207. {
  208.     int dummy_token = -1;
  209.  
  210.     if (!term)            /* unknown */
  211.     int_error("use 'set term' to set terminal type first", c_token);
  212.  
  213.     is_3d_plot = FALSE;
  214.  
  215.     if (parametric && strcmp(dummy_var[0], "u") == 0)
  216.     strcpy(dummy_var[0], "t");
  217.  
  218.     /* initialise the arrays from the 'set' scalars */
  219.  
  220.     INIT_ARRAYS(FIRST_X_AXIS, xmin, xmax, autoscale_x, is_log_x, base_log_x, log_base_log_x, 0);
  221.     INIT_ARRAYS(FIRST_Y_AXIS, ymin, ymax, autoscale_y, is_log_y, base_log_y, log_base_log_y, 1);
  222.     INIT_ARRAYS(SECOND_X_AXIS, x2min, x2max, autoscale_x2, is_log_x2, base_log_x2, log_base_log_x2, 0);
  223.     INIT_ARRAYS(SECOND_Y_AXIS, y2min, y2max, autoscale_y2, is_log_y2, base_log_y2, log_base_log_y2, 1);
  224.  
  225.     min_array[T_AXIS] = tmin;
  226.     max_array[T_AXIS] = tmax;
  227.  
  228.     if (equals(c_token, "[")) {
  229.     c_token++;
  230.     if (isletter(c_token)) {
  231.         if (equals(c_token + 1, "=")) {
  232.         dummy_token = c_token;
  233.         c_token += 2;
  234.         } else {
  235.         /* oops; probably an expression with a variable. */
  236.         /* Parse it as an xmin expression. */
  237.         /* used to be: int_error("'=' expected",c_token); */
  238.         }
  239.     } {
  240.         int axis = (parametric || polar) ? T_AXIS : FIRST_X_AXIS;
  241.  
  242.  
  243.         auto_array[axis] = load_range(axis, &min_array[axis], &max_array[axis], auto_array[axis]);
  244.         if (!equals(c_token, "]"))
  245.         int_error("']' expected", c_token);
  246.         c_token++;
  247.     }            /* end of scope of 'axis' */
  248.     }                /* first '[' */
  249.     if (parametric || polar)    /* set optional x ranges */
  250.     LOAD_RANGE(FIRST_X_AXIS);
  251.     else {
  252.     /* order of t doesn't matter, but x does */
  253.     CHECK_REVERSE(FIRST_X_AXIS);
  254.     }
  255.  
  256.     LOAD_RANGE(FIRST_Y_AXIS);
  257.     CHECK_REVERSE(FIRST_Y_AXIS);
  258.     LOAD_RANGE(SECOND_X_AXIS);
  259.     CHECK_REVERSE(SECOND_X_AXIS);
  260.     LOAD_RANGE(SECOND_Y_AXIS);
  261.     CHECK_REVERSE(SECOND_Y_AXIS);
  262.  
  263.     /* use the default dummy variable unless changed */
  264.     if (dummy_token >= 0)
  265.     copy_str(c_dummy_var[0], dummy_token, MAX_ID_LEN);
  266.     else
  267.     (void) strcpy(c_dummy_var[0], dummy_var[0]);
  268.  
  269.     eval_plots();
  270. }
  271.  
  272. /* Use up to 7 columns in data file at once -- originally it was 5 */
  273. #define NCOL 7
  274.  
  275.  
  276. /* A quick note about boxes style. For boxwidth auto, we cannot
  277.  * calculate widths yet, since it may be sorted, etc. But if
  278.  * width is set, we must do it now, before logs of xmin/xmax
  279.  * are taken.
  280.  * We store -1 in point->z as a marker to mean width needs to be
  281.  * calculated, or 0 to mean that xmin/xmax are set correctly
  282.  */
  283.  
  284.  
  285. static void get_data(this_plot)
  286. struct curve_points *this_plot;
  287. /* this_plot->token is after datafile spec, for error reporting
  288.  * it will later be moved passed title/with/linetype/pointtype
  289.  */
  290. {
  291.     register int i /* num. points ! */ , j, col;
  292.     double v[NCOL];
  293.     int storetoken = this_plot->token;
  294.  
  295.     /* eval_plots has already opened file */
  296.  
  297.     switch (this_plot->plot_style) {    /* set maximum columns to scan */
  298.     case XYERRORBARS:
  299.     case BOXXYERROR:
  300.     col = 7;
  301.     break;
  302.  
  303.     case BOXERROR:
  304.     case FINANCEBARS:
  305.     case CANDLESTICKS:
  306.     col = 5;
  307.     break;
  308.  
  309.     case XERRORBARS:
  310.     case YERRORBARS:
  311.     case VECTOR:
  312.     col = 4;
  313.     break;
  314.  
  315.     case BOXES:
  316.     col = 4;
  317.     break;
  318.  
  319.     default:
  320.     col = 2;
  321.     }
  322.  
  323.     if (this_plot->plot_smooth == ACSPLINES)
  324.     col = 3;
  325.  
  326.     if (df_no_use_specs > col)
  327.     fputs("warning : too many using specs for this style\n", stderr);
  328.  
  329.     i = 0;
  330.     while ((j = df_readline(v, col)) != DF_EOF) {
  331.     /* j <= col */
  332.  
  333.     if (i >= this_plot->p_max) {
  334.         /*
  335.          * overflow about to occur. Extend size of points[] array. We
  336.          * either double the size, or add 1000 points, whichever is a
  337.          * smaller increment. Note i = p_max.
  338.          */
  339.         cp_extend(this_plot, i + (i < 1000 ? i : 1000));
  340.     }
  341.     /* Limitation: No xerrorbars with boxes */
  342.     switch (j) {
  343.     default:
  344.         {
  345.         char message[80];
  346.         sprintf(message, "internal error : df_readline returned %d : datafile line %d", j, df_line_number);
  347.         df_close();
  348.         int_error(message, c_token);
  349.         }
  350.     case DF_UNDEFINED:
  351.         /* bad result from extended using expression */
  352.         this_plot->points[i].type = UNDEFINED;
  353.         i++;
  354.         continue;
  355.  
  356.     case DF_FIRST_BLANK:
  357.         /* break in data, make next point undefined */
  358.         this_plot->points[i].type = UNDEFINED;
  359.         i++;
  360.         continue;
  361.  
  362.     case DF_SECOND_BLANK:
  363.         /* second blank line. We dont do anything
  364.          * (we did everything when we got FIRST one)
  365.          */
  366.         continue;
  367.  
  368.     case 0:        /* not blank line, but df_readline couldn't parse it */
  369.         {
  370.         char message[80];
  371.         sprintf(message, "Bad data on line %d", df_line_number);
  372.         df_close();
  373.         int_error(message, this_plot->token);
  374.         }
  375.  
  376.     case 1:
  377.         {            /* only one number */
  378.         /* x is index, assign number to y */
  379.         v[1] = v[0];
  380.         v[0] = df_datum;
  381.         /* nobreak */
  382.         }
  383.  
  384.     case 2:
  385.         /* x, y */
  386.         /* ylow and yhigh are same as y */
  387.  
  388.         if (this_plot->plot_style == BOXES && boxwidth > 0) {
  389.         /* calc width now */
  390.         store2d_point(this_plot, i++, v[0], v[1], v[0] - boxwidth / 2, v[0] + boxwidth / 2, v[1], v[1], 0.0);
  391.         } else {
  392.         /* xlow and xhigh are same as x */
  393.         store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1],
  394.                   -1.0);    /* auto width if boxes, else ignored */
  395.         }
  396.         break;
  397.  
  398.  
  399.     case 3:
  400.         /* x, y, ydelta OR x, y, xdelta OR x, y, width */
  401.         if (this_plot->plot_smooth == ACSPLINES)
  402.         store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1], v[1], v[2]);
  403.         else
  404.         switch (this_plot->plot_style) {
  405.         default:
  406.             int_warn("This plot style not work with 3 cols. Setting to yerrorbars", storetoken);
  407.             this_plot->plot_style = YERRORBARS;
  408.             /* fall through */
  409.  
  410.         case YERRORBARS:
  411.         case BOXERROR:    /* x, y, dy */
  412.             store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1] - v[2], v[1] + v[2],
  413.                   -1.0);    /* auto width if boxes, else ignored */
  414.             break;
  415.  
  416.         case XERRORBARS:
  417.             store2d_point(this_plot, i++, v[0], v[1], v[0] - v[2], v[0] + v[2], v[1], v[1], 0.0);
  418.             break;
  419.  
  420.         case BOXES:
  421.             /* calculate xmin and xmax here, so that logs are taken if
  422.              * if necessary
  423.              */
  424.             store2d_point(this_plot, i++, v[0], v[1], v[0] - v[2] / 2, v[0] + v[2] / 2, v[1], v[1], 0.0);
  425.             break;
  426.  
  427.         }        /*inner switch */
  428.  
  429.         break;
  430.  
  431.  
  432.  
  433.     case 4:
  434.         /* x, y, ylow, yhigh OR
  435.          * x, y, xlow, xhigh OR
  436.          * x, y, xdelta, ydelta OR
  437.          * x, y, ydelta, width
  438.          */
  439.  
  440.         switch (this_plot->plot_style) {
  441.         default:
  442.         int_warn("This plot style does not work with 4 cols. Setting to yerrorbars",
  443.              storetoken);
  444.         this_plot->plot_style = YERRORBARS;
  445.         /* fall through */
  446.  
  447.         case YERRORBARS:
  448.         store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], -1.0);
  449.         break;
  450.  
  451.         case BOXXYERROR:    /* x, y, dx, dy */
  452.         case XYERRORBARS:
  453.         store2d_point(this_plot, i++, v[0], v[1], v[0] - v[2], v[0] + v[2], v[1] - v[3], v[1] + v[3], 0.0);
  454.         break;
  455.  
  456.  
  457.         case BOXES:    /* x, y, xmin, xmax */
  458.         store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[1], v[1], 0.0);
  459.         break;
  460.  
  461.         case XERRORBARS:
  462.         store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[1], v[1], 0.0);
  463.         break;
  464.  
  465.         case BOXERROR:
  466.         /* x,y, xleft, xright */
  467.         store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[1] - v[2], v[1] + v[2], 0.0);
  468.         break;
  469.  
  470.         case VECTOR:
  471.         /* x,y,dx,dy */
  472.         store2d_point(this_plot, i++, v[0], v[1], v[0], v[0] + v[2], v[1], v[1] + v[3], -1.0);
  473.         break;
  474.         }            /*inner switch */
  475.  
  476.         break;
  477.  
  478.  
  479.     case 5:
  480.         {            /* x, y, ylow, yhigh, width  or  x open low high close */
  481.         switch (this_plot->plot_style) {
  482.         default:
  483.             int_warn("Five col. plot style must be boxerrorbars, financebars or candlesticks. Setting to boxerrorbars", storetoken);
  484.             this_plot->plot_style = BOXERROR;
  485.             /*fall through */
  486.  
  487.         case BOXERROR:    /* x, y, ylow, yhigh, width */
  488.             store2d_point(this_plot, i++, v[0], v[1], v[0] - v[4] / 2, v[0] + v[4] / 2, v[2], v[3], 0.0);
  489.             break;
  490.  
  491.         case FINANCEBARS:
  492.         case CANDLESTICKS:
  493.             store2d_point(this_plot, i++, v[0], v[1], v[0], v[0], v[2], v[3], v[4]);
  494.             break;
  495.         }
  496.         break;
  497.         }
  498.  
  499.     case 7:
  500.         /* same as six columns. Width ignored */
  501.         /* eh ? - fall through */
  502.     case 6:
  503.         /* x, y, xlow, xhigh, ylow, yhigh */
  504.         switch (this_plot->plot_style) {
  505.         default:
  506.         int_warn("This plot style not work with 6 cols. Setting to xyerrorbars", storetoken);
  507.         this_plot->plot_style = XYERRORBARS;
  508.         /*fall through */
  509.         case XYERRORBARS:
  510.         case BOXXYERROR:
  511.         store2d_point(this_plot, i++, v[0], v[1], v[2], v[3], v[4], v[5], 0.0);
  512.         break;
  513.         }
  514.  
  515.     }            /*switch */
  516.  
  517.     }                /*while */
  518.  
  519.     this_plot->p_count = i;
  520.     cp_extend(this_plot, i);    /* shrink to fit */
  521.  
  522.     df_close();
  523. }
  524.  
  525. /* called by get_data for each point */
  526. static void store2d_point(this_plot, i, x, y, xlow, xhigh, ylow, yhigh, width)
  527. struct curve_points *this_plot;
  528. int i;                /* point number */
  529. double x, y;
  530. double ylow, yhigh;
  531. double xlow, xhigh;
  532. double width;            /* -1 means autocalc, 0 means use xmin/xmax */
  533. {
  534.     struct coordinate GPHUGE *cp = &(this_plot->points[i]);
  535.     int dummy_type = INRANGE;    /* sometimes we dont care about outranging */
  536.  
  537.  
  538.     /* jev -- pass data values thru user-defined function */
  539.     /* div -- y is dummy variable 2 - copy value there */
  540.     if (ydata_func.at) {
  541.     struct value val;
  542.  
  543.     (void) Gcomplex(&ydata_func.dummy_values[0], y, 0.0);
  544.     ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
  545.     evaluate_at(ydata_func.at, &val);
  546.     y = undefined ? 0.0 : real(&val);
  547.  
  548.     (void) Gcomplex(&ydata_func.dummy_values[0], ylow, 0.0);
  549.     ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
  550.     evaluate_at(ydata_func.at, &val);
  551.     ylow = undefined ? 0 : real(&val);
  552.  
  553.     (void) Gcomplex(&ydata_func.dummy_values[0], yhigh, 0.0);
  554.     ydata_func.dummy_values[2] = ydata_func.dummy_values[0];
  555.     evaluate_at(ydata_func.at, &val);
  556.     yhigh = undefined ? 0 : real(&val);
  557.     }
  558.     dummy_type = cp->type = INRANGE;
  559.  
  560.     if (polar) {
  561.     double newx, newy;
  562.     if (!(autoscale_r & 2) && y > rmax) {
  563.         cp->type = OUTRANGE;
  564.     }
  565.     if (!(autoscale_r & 1)) {
  566.         /* we store internally as if plotting r(t)-rmin */
  567.         y -= rmin;
  568.     }
  569.     newx = y * cos(x * ang2rad);
  570.     newy = y * sin(x * ang2rad);
  571. #if 0 /* HBB 981118: added polar errorbars */
  572.     /* only lines and points supported with polar */
  573.     y = ylow = yhigh = newy;
  574.     x = xlow = xhigh = newx;
  575. #else 
  576.     y = newy;
  577.     x = newx;
  578.  
  579.     if (!(autoscale_r & 2) && yhigh > rmax) {
  580.         cp->type = OUTRANGE;
  581.     }
  582.     if (!(autoscale_r & 1)) {
  583.         /* we store internally as if plotting r(t)-rmin */
  584.         yhigh -= rmin;
  585.     }
  586.     newx = yhigh * cos(xhigh * ang2rad);
  587.     newy = yhigh * sin(xhigh * ang2rad);
  588.     yhigh = newy;
  589.     xhigh = newx;
  590.  
  591.     if (!(autoscale_r & 2) && ylow > rmax) {
  592.         cp->type = OUTRANGE;
  593.     }
  594.     if (!(autoscale_r & 1)) {
  595.         /* we store internally as if plotting r(t)-rmin */
  596.         ylow -= rmin;
  597.     }
  598.     newx = ylow * cos(xlow * ang2rad);
  599.     newy = ylow * sin(xlow * ang2rad);
  600.     ylow = newy;
  601.     xlow = newx;
  602. #endif
  603.     }
  604.     /* return immediately if x or y are undefined
  605.      * we dont care if outrange for high/low.
  606.      * BUT if high/low undefined (ie log( < 0 ), no number is stored,
  607.      * but graphics.c doesn't know.
  608.      * explicitly store -VERYLARGE;
  609.      */
  610.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->x, x, cp->type, this_plot->x_axis, NOOP, return);
  611.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->xlow, xlow, dummy_type, this_plot->x_axis, NOOP, cp->xlow = -VERYLARGE);
  612.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->xhigh, xhigh, dummy_type, this_plot->x_axis, NOOP, cp->xhigh = -VERYLARGE);
  613.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->y, y, cp->type, this_plot->y_axis, NOOP, return);
  614.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->ylow, ylow, dummy_type, this_plot->y_axis, NOOP, cp->ylow = -VERYLARGE);
  615.     STORE_WITH_LOG_AND_FIXUP_RANGE(cp->yhigh, yhigh, dummy_type, this_plot->y_axis, NOOP, cp->yhigh = -VERYLARGE);
  616.     cp->z = width;
  617. }                /* store2d_point */
  618.  
  619.  
  620.  
  621. /*
  622.  * print_points: a debugging routine to print out the points of a curve, and
  623.  * the curve structure. If curve<0, then we print the list of curves.
  624.  */
  625.  
  626. #if 0                /* not used */
  627. static char *plot_type_names[4] =
  628. {
  629.     "Function", "Data", "3D Function", "3d data"
  630. };
  631. static char *plot_style_names[14] =
  632. {
  633.     "Lines", "Points", "Impulses", "LinesPoints", "Dots", "XErrorbars",
  634.  "YErrorbars", "XYErrorbars", "BoxXYError", "Boxes", "Boxerror", "Steps",
  635.     "FSteps", "Vector"
  636. };
  637. static char *plot_smooth_names[5] =
  638. {
  639.     "None", "Unique", "CSplines", "ACSplines", "Bezier", "SBezier"
  640. };
  641.  
  642. static void print_points(curve)
  643. int curve;            /* which curve to print */
  644. {
  645.     register struct curve_points *this_plot;
  646.     int i;
  647.  
  648.     if (curve < 0) {
  649.     for (this_plot = first_plot, i = 0;
  650.          this_plot != NULL;
  651.          i++, this_plot = this_plot->next_cp) {
  652.         printf("Curve %d:\n", i);
  653.         if ((int) this_plot->plot_type >= 0 && (int) (this_plot->plot_type) < 4)
  654.         printf("Plot type %d: %s\n", (int) (this_plot->plot_type),
  655.                plot_type_names[(int) (this_plot->plot_type)]);
  656.         else
  657.         printf("Plot type %d: BAD\n", (int) (this_plot->plot_type));
  658.         if ((int) this_plot->plot_style >= 0 && (int) (this_plot->plot_style) < 14)
  659.         printf("Plot style %d: %s\n", (int) (this_plot->plot_style),
  660.                plot_style_names[(int) (this_plot->plot_style)]);
  661.         else
  662.         printf("Plot style %d: BAD\n", (int) (this_plot->plot_style));
  663.         if ((int) this_plot->plot_smooth >= 0 && (int) (this_plot->plot_smooth) < 6)
  664.         printf("Plot smooth style %d: %s\n", (int) (this_plot->plot_style),
  665.                plot_smooth_names[(int) (this_plot->plot_smooth)]);
  666.         else
  667.         printf("Plot smooth style %d: BAD\n", (int) (this_plot->plot_smooth));
  668.         printf("Plot title: '%s'\n", this_plot->title);
  669.         printf("Line type %d\n", this_plot->line_type);
  670.         printf("Point type %d\n", this_plot->point_type);
  671.         printf("max points %d\n", this_plot->p_max);
  672.         printf("current points %d\n", this_plot->p_count);
  673.         printf("\n");
  674.     }
  675.     } else {
  676.     for (this_plot = first_plot, i = 0;
  677.          i < curve && this_plot != NULL;
  678.          i++, this_plot = this_plot->next_cp);
  679.     if (this_plot == NULL)
  680.         printf("Curve %d does not exist; list has %d curves\n", curve, i);
  681.     else {
  682.         printf("Curve %d, %d points\n", curve, this_plot->p_count);
  683.         for (i = 0; i < this_plot->p_count; i++) {
  684.         printf("%c x=%g y=%g z=%g xlow=%g xhigh=%g ylow=%g yhigh=%g\n",
  685.                this_plot->points[i].type == INRANGE ? 'i'
  686.                : this_plot->points[i].type == OUTRANGE ? 'o'
  687.                : 'u',
  688.                this_plot->points[i].x,
  689.                this_plot->points[i].y,
  690.                this_plot->points[i].z,
  691.                this_plot->points[i].xlow,
  692.                this_plot->points[i].xhigh,
  693.                this_plot->points[i].ylow,
  694.                this_plot->points[i].yhigh);
  695.         }
  696.         printf("\n");
  697.     }
  698.     }
  699. }
  700. #endif /* not used */
  701.  
  702. static void print_table(this_plot, plot_num)
  703. struct curve_points *this_plot;
  704. int plot_num;
  705. {
  706.     int i, curve;
  707.  
  708.     for (curve = 0; curve < plot_num;
  709.      curve++, this_plot = this_plot->next_cp) {
  710.     fprintf(gpoutfile, "#Curve %d, %d points\n#x y type\n", curve, this_plot->p_count);
  711.     for (i = 0; i < this_plot->p_count; i++) {
  712.         fprintf(gpoutfile, "%g %g %c\n",
  713.             this_plot->points[i].x,
  714.             this_plot->points[i].y,
  715.             this_plot->points[i].type == INRANGE ? 'i'
  716.             : this_plot->points[i].type == OUTRANGE ? 'o'
  717.             : 'u');
  718.     }
  719.     fputc('\n', gpoutfile);
  720.     }
  721. /* two blank lines between plots in table output */
  722.     fputc('\n', gpoutfile);
  723.     fflush(gpoutfile);
  724. }
  725.  
  726. /*
  727.  * This parses the plot command after any range specifications. To support
  728.  * autoscaling on the x axis, we want any data files to define the x range,
  729.  * then to plot any functions using that range. We thus parse the input
  730.  * twice, once to pick up the data files, and again to pick up the functions.
  731.  * Definitions are processed twice, but that won't hurt.
  732.  * div - okay, it doesn't hurt, but every time an option as added for
  733.  * datafiles, code to parse it has to be added here. Change so that
  734.  * we store starting-token in the plot structure.
  735.  */
  736. static void eval_plots()
  737. {
  738.     register int i;
  739.     register struct curve_points *this_plot, **tp_ptr;
  740.  
  741.     int some_functions = 0;
  742.     int plot_num, line_num, point_num, xparam = 0;
  743.     char *xtitle;
  744.     int begin_token = c_token;    /* so we can rewind for second pass */
  745.  
  746.     int uses_axis[AXIS_ARRAY_SIZE];
  747.  
  748.     uses_axis[FIRST_X_AXIS] =
  749.     uses_axis[FIRST_Y_AXIS] =
  750.     uses_axis[SECOND_X_AXIS] =
  751.     uses_axis[SECOND_Y_AXIS] = 0;
  752.  
  753.     /* Reset first_plot. This is usually done at the end of this function.
  754.        If there is an error within this function, the memory is left allocated,
  755.        since we cannot call cp_free if the list is incomplete. Making sure that
  756.        the list structure is always vaild requires some rewriting */
  757.     first_plot = NULL;
  758.  
  759.     tp_ptr = &(first_plot);
  760.     plot_num = 0;
  761.     line_num = 0;        /* default line type */
  762.     point_num = 0;        /* default point type */
  763.  
  764.     xtitle = NULL;
  765.  
  766.     /*** First Pass: Read through data files ***
  767.      * This pass serves to set the xrange and to parse the command, as well
  768.      * as filling in every thing except the function data. That is done after
  769.      * the xrange is defined.
  770.      */
  771.     while (TRUE) {
  772.     if (END_OF_COMMAND)
  773.         int_error("function to plot expected", c_token);
  774.  
  775.     if (is_definition(c_token)) {
  776.         define();
  777.     } else {
  778.         int x_axis = 0, y_axis = 0;
  779.         int specs;
  780.  
  781.         /* for datafile plot, record datafile spec for title */
  782.         int start_token = c_token, end_token;
  783.  
  784.         plot_num++;
  785.  
  786.         if (isstring(c_token)) {    /* data file to plot */
  787.  
  788.         if (parametric && xparam)
  789.             int_error("previous parametric function not fully specified", c_token);
  790.  
  791.         if (*tp_ptr)
  792.             this_plot = *tp_ptr;
  793.         else {        /* no memory malloc()'d there yet */
  794.             this_plot = cp_alloc(MIN_CRV_POINTS);
  795.             *tp_ptr = this_plot;
  796.         }
  797.         this_plot->plot_type = DATA;
  798.         this_plot->plot_style = data_style;
  799.         this_plot->plot_smooth = NONE;
  800.  
  801.         specs = df_open(NCOL);    /* up to NCOL cols */
  802.         /* this parses data-file-specific modifiers only */
  803.         /* we'll sort points when we know style, if necessary */
  804.         if (df_binary)
  805.             int_error("2d binary files not yet supported", c_token);
  806.  
  807.         this_plot->token = end_token = c_token - 1;    /* include modifiers in default title */
  808.  
  809.         } else {
  810.  
  811.         /* function to plot */
  812.  
  813.         some_functions = 1;
  814.         if (parametric)    /* working on x parametric function */
  815.             xparam = 1 - xparam;
  816.         if (*tp_ptr) {
  817.             this_plot = *tp_ptr;
  818.             cp_extend(this_plot, samples + 1);
  819.         } else {    /* no memory malloc()'d there yet */
  820.             this_plot = cp_alloc(samples + 1);
  821.             *tp_ptr = this_plot;
  822.         }
  823.         this_plot->plot_type = FUNC;
  824.         this_plot->plot_style = func_style;
  825.         dummy_func = &plot_func;
  826.         plot_func.at = temp_at();
  827.         dummy_func = NULL;
  828.         /* ignore it for now */
  829.         end_token = c_token - 1;
  830.         }            /* end of IS THIS A FILE OR A FUNC block */
  831.  
  832.  
  833.         /*  deal with smooth */
  834.         if (almost_equals(c_token, "s$mooth")) {
  835.  
  836.         if (END_OF_COMMAND)
  837.             int_error("expecting smooth parameter", c_token);
  838.         else {
  839.             c_token++;
  840.             if (almost_equals(c_token, "u$nique"))
  841.             this_plot->plot_smooth = UNIQUE;
  842.             else if (almost_equals(c_token, "a$csplines"))
  843.             this_plot->plot_smooth = ACSPLINES;
  844.             else if (almost_equals(c_token, "c$splines"))
  845.             this_plot->plot_smooth = CSPLINES;
  846.             else if (almost_equals(c_token, "b$ezier"))
  847.             this_plot->plot_smooth = BEZIER;
  848.             else if (almost_equals(c_token, "s$bezier"))
  849.             this_plot->plot_smooth = SBEZIER;
  850.             else
  851.             int_error("expecting 'unique', 'acsplines', 'csplines', 'bezier' or 'sbezier'", c_token);
  852.         }
  853.         this_plot->plot_style = LINES;
  854.         c_token++;    /* skip format */
  855.         }
  856.         /* look for axes/axis */
  857.  
  858.         if (almost_equals(c_token, "ax$es") || almost_equals(c_token, "ax$is")) {
  859.         if (parametric && xparam)
  860.             int_error("previous parametric function not fully specified", c_token);
  861.  
  862.         if (equals(++c_token, "x1y1")) {
  863.             x_axis = FIRST_X_AXIS;
  864.             y_axis = FIRST_Y_AXIS;
  865.             ++c_token;
  866.         } else if (equals(c_token, "x2y2")) {
  867.             x_axis = SECOND_X_AXIS;
  868.             y_axis = SECOND_Y_AXIS;
  869.             ++c_token;
  870.         } else if (equals(c_token, "x1y2")) {
  871.             x_axis = FIRST_X_AXIS;
  872.             y_axis = SECOND_Y_AXIS;
  873.             ++c_token;
  874.         } else if (equals(c_token, "x2y1")) {
  875.             x_axis = SECOND_X_AXIS;
  876.             y_axis = FIRST_Y_AXIS;
  877.             ++c_token;
  878.         } else
  879.             int_error("axes must be x1y1, x1y2, x2y1 or x2y2", c_token);
  880.         } else {
  881.         x_axis = FIRST_X_AXIS;
  882.         y_axis = FIRST_Y_AXIS;
  883.         }
  884.  
  885.  
  886.         this_plot->x_axis = x_axis;
  887.         this_plot->y_axis = y_axis;
  888.  
  889.         /* we can now do some checks that we deferred earlier */
  890.  
  891.         if (this_plot->plot_type == DATA) {
  892.         if (!(uses_axis[x_axis] & 1) && autoscale_lx) {
  893.             if (auto_array[x_axis] & 1)
  894.             min_array[x_axis] = VERYLARGE;
  895.             if (auto_array[x_axis] & 2)
  896.             max_array[x_axis] = -VERYLARGE;
  897.         }
  898.         if (datatype[x_axis] == TIME) {
  899.             if (specs < 2)
  900.             int_error("Need full using spec for x time data", c_token);
  901.             df_timecol[0] = 1;
  902.         }
  903.         if (datatype[y_axis] == TIME) {
  904.             if (specs < 1)
  905.             int_error("Need using spec for y time data", c_token);
  906.             df_timecol[y_axis] = 1;    /* need other cols, but I'm lazy */
  907.         }
  908.         uses_axis[x_axis] |= 1;        /* separate record of datafile and func */
  909.         uses_axis[y_axis] |= 1;
  910.         } else if (!parametric || !xparam) {
  911.         /* for x part of a parametric function, axes are possibly wrong */
  912.         uses_axis[x_axis] |= 2;        /* separate record of data and func */
  913.         uses_axis[y_axis] |= 2;
  914.         }
  915.         if (almost_equals(c_token, "t$itle")) {
  916.         if (parametric) {
  917.             if (xparam)
  918.             int_error("\"title\" allowed only after parametric function fully specified", c_token);
  919.             else if (xtitle != NULL)
  920.             xtitle[0] = '\0';    /* Remove default title . */
  921.         }
  922.         c_token++;
  923.         if (isstring(c_token)) {
  924.             m_quote_capture(&(this_plot->title), c_token, c_token);
  925.         } else {
  926.             int_error("expecting \"title\" for plot", c_token);
  927.         }
  928.         c_token++;
  929.         } else if (almost_equals(c_token, "not$itle")) {
  930.         if (xtitle != NULL)
  931.             xtitle[0] = '\0';
  932.         c_token++;
  933.         } else {
  934.         m_capture(&(this_plot->title), start_token, end_token);
  935.         if (xparam)
  936.             xtitle = this_plot->title;
  937.         }
  938.  
  939.  
  940.         if (almost_equals(c_token, "w$ith")) {
  941.         if (parametric && xparam)
  942.             int_error("\"with\" allowed only after parametric function fully specified", c_token);
  943.         this_plot->plot_style = get_style();
  944.         }
  945.         /* pick up line/point specs
  946.          * - point spec allowed if style uses points, ie style&2 != 0
  947.          * - keywords for lt and pt are optional
  948.          */
  949.         LP_PARSE(this_plot->lp_properties, 1, this_plot->plot_style & 2,
  950.              line_num, point_num);
  951.  
  952.         /* allow old-style syntax too - ignore case lt 3 4 for example */
  953.         if (!equals(c_token, ",") && !END_OF_COMMAND) {
  954.         struct value t;
  955.         this_plot->lp_properties.l_type =
  956.             this_plot->lp_properties.p_type = (int) real(const_express(&t)) - 1;
  957.  
  958.         if (!equals(c_token, ",") && !END_OF_COMMAND)
  959.             this_plot->lp_properties.p_type = (int) real(const_express(&t)) - 1;
  960.         }
  961.         if (!xparam) {
  962.         if (this_plot->plot_style & 2)    /* style includes points */
  963.             ++point_num;
  964.         ++line_num;
  965.         }
  966.         if (this_plot->plot_type == DATA) {
  967.         /* actually get the data now */
  968.         get_data(this_plot);
  969.  
  970.         /* sort */
  971.         switch (this_plot->plot_smooth) {    /* sort and average, if */
  972.         case UNIQUE:    /* the style requires   */
  973.         case CSPLINES:
  974.         case ACSPLINES:
  975.         case SBEZIER:
  976.             sort_points(this_plot);
  977.             cp_implode(this_plot);
  978.             break;
  979.         default:
  980.             ;        /* keep gcc -Wall happy */
  981.         }
  982.         switch (this_plot->plot_smooth) {    /* create new data set     */
  983.         case SBEZIER:    /* by evaluation of        */
  984.         case BEZIER:    /* interpolation routines  */
  985.         case ACSPLINES:
  986.         case CSPLINES:
  987.             gen_interp(this_plot);
  988.             break;
  989.         default:
  990.             ;        /* keep gcc -Wall happy */
  991.         }
  992.  
  993.         /* now that we know the plot style, adjust the x- and yrange */
  994.         /* adjust_range(this_plot); no longer needed */
  995.         }
  996.         this_plot->token = c_token;        /* save end of plot for second pass */
  997.         tp_ptr = &(this_plot->next_cp);
  998.  
  999.     }            /* !is_defn */
  1000.  
  1001.     if (equals(c_token, ","))
  1002.         c_token++;
  1003.     else
  1004.         break;
  1005.     }
  1006.  
  1007.     if (parametric && xparam)
  1008.     int_error("parametric function not fully specified", NO_CARET);
  1009.  
  1010.  
  1011. /*** Second Pass: Evaluate the functions ***/
  1012.     /*
  1013.      * Everything is defined now, except the function data. We expect no
  1014.      * syntax errors, etc, since the above parsed it all. This makes the code
  1015.      * below simpler. If autoscale_ly, the yrange may still change.
  1016.      * we stored last token of each plot, so we dont need to do everything again
  1017.      */
  1018.  
  1019.     /* give error if xrange badly set from missing datafile error
  1020.      * parametric or polar fns can still affect x ranges
  1021.      */
  1022.  
  1023.     if (!parametric && !polar) {
  1024.     if (min_array[FIRST_X_AXIS] == VERYLARGE ||
  1025.         max_array[FIRST_X_AXIS] == -VERYLARGE)
  1026.         int_error("x range is invalid", c_token);
  1027.     /* check that xmin -> xmax is not too small */
  1028.     fixup_range(FIRST_X_AXIS, "x");
  1029.  
  1030.     if (uses_axis[SECOND_X_AXIS] & 1) {
  1031.         /* some data plots with x2 */
  1032.         if (min_array[SECOND_X_AXIS] == VERYLARGE ||
  1033.         max_array[SECOND_X_AXIS] == -VERYLARGE)
  1034.         int_error("x2 range is invalid", c_token);
  1035.         /* check that x2min -> x2max is not too small */
  1036.         fixup_range(SECOND_X_AXIS, "x2");
  1037.     } else if (auto_array[SECOND_X_AXIS]) {
  1038.         /* copy x1's range */
  1039.         if (auto_array[SECOND_X_AXIS] & 1)
  1040.         min_array[SECOND_X_AXIS] = min_array[FIRST_X_AXIS];
  1041.         if (auto_array[SECOND_X_AXIS] & 2)
  1042.         max_array[SECOND_X_AXIS] = max_array[FIRST_X_AXIS];
  1043.     }
  1044.     }
  1045.     if (some_functions) {
  1046.  
  1047.     /* call the controlled variable t, since x_min can also mean smallest x */
  1048.     double t_min, t_max, t_step;
  1049.  
  1050.     if (parametric || polar) {
  1051.         if (!(uses_axis[FIRST_X_AXIS] & 1)) {
  1052.         /* these have not yet been set to full width */
  1053.         if (auto_array[FIRST_X_AXIS] & 1)
  1054.             min_array[FIRST_X_AXIS] = VERYLARGE;
  1055.         if (auto_array[FIRST_X_AXIS] & 2)
  1056.             max_array[FIRST_X_AXIS] = -VERYLARGE;
  1057.         }
  1058.         if (!(uses_axis[SECOND_X_AXIS] & 1)) {
  1059.         if (auto_array[SECOND_X_AXIS] & 1)
  1060.             min_array[SECOND_X_AXIS] = VERYLARGE;
  1061.         if (auto_array[SECOND_X_AXIS] & 2)
  1062.             max_array[SECOND_X_AXIS] = -VERYLARGE;
  1063.         }
  1064.     }
  1065. #define SET_DUMMY_RANGE(AXIS) \
  1066. do{ assert(!polar && !parametric); \
  1067.  if (log_array[AXIS]) {\
  1068.   if (min_array[AXIS] <= 0.0 || max_array[AXIS] <= 0.0)\
  1069.    int_error("x/x2 range must be greater than 0 for log scale!", NO_CARET);\
  1070.   t_min = log(min_array[AXIS])/log_base_array[AXIS]; t_max = log(max_array[AXIS])/log_base_array[AXIS];\
  1071.  } else {\
  1072.   t_min = min_array[AXIS]; t_max = max_array[AXIS];\
  1073.  }\
  1074.  t_step = (t_max - t_min) / (samples - 1); \
  1075. }while(0)
  1076.  
  1077.     if (parametric || polar) {
  1078.         t_min = min_array[T_AXIS];
  1079.         t_max = max_array[T_AXIS];
  1080.         t_step = (t_max - t_min) / (samples - 1);
  1081.     }
  1082.     /* else we'll do it on each plot */
  1083.  
  1084.     tp_ptr = &(first_plot);
  1085.     plot_num = 0;
  1086.     this_plot = first_plot;
  1087.     c_token = begin_token;    /* start over */
  1088.  
  1089.     /* Read through functions */
  1090.     while (TRUE) {
  1091.         if (is_definition(c_token)) {
  1092.         define();
  1093.         } else {
  1094.         int x_axis = this_plot->x_axis;
  1095.         int y_axis = this_plot->y_axis;
  1096.  
  1097.         plot_num++;
  1098.         if (!isstring(c_token)) {    /* function to plot */
  1099.             if (parametric) {    /* toggle parametric axes */
  1100.             xparam = 1 - xparam;
  1101.             }
  1102.             dummy_func = &plot_func;
  1103.             plot_func.at = temp_at();    /* reparse function */
  1104.  
  1105.             if (!parametric && !polar) {
  1106.             SET_DUMMY_RANGE(x_axis);
  1107.             }
  1108.             for (i = 0; i < samples; i++) {
  1109.             double temp;
  1110.             struct value a;
  1111.             double t = t_min + i * t_step;
  1112.             /* parametric/polar => NOT a log quantity */
  1113.             double x = (!parametric && !polar &&
  1114.                     log_array[x_axis]) ? pow(base_array[x_axis], t) : t;
  1115.  
  1116.             (void) Gcomplex(&plot_func.dummy_values[0], x, 0.0);
  1117.             evaluate_at(plot_func.at, &a);
  1118.  
  1119.             if (undefined || (fabs(imag(&a)) > zero)) {
  1120.                 this_plot->points[i].type = UNDEFINED;
  1121.                 continue;
  1122.             }
  1123.             temp = real(&a);
  1124.  
  1125.             this_plot->points[i].z = -1.0;    /* width of box not specified */
  1126.             this_plot->points[i].type = INRANGE;    /* for the moment */
  1127.  
  1128.             if (parametric) {
  1129.                 /* we cannot do range-checking now, since for
  1130.                  * the x function we did not know which axes
  1131.                  * we were using
  1132.                  * DO NOT TAKE LOGS YET - do it in parametric_fixup
  1133.                  */
  1134.                 this_plot->points[i].x = t;        /* ignored, actually... */
  1135.                 this_plot->points[i].y = temp;
  1136.             } else if (polar) {
  1137.                 double y;
  1138.                 if (!(autoscale_r & 2) && temp > rmax)
  1139.                 this_plot->points[i].type = OUTRANGE;
  1140.                 if (!(autoscale_r & 1))
  1141.                 temp -= rmin;
  1142.                 y = temp * sin(x * ang2rad);
  1143.                 x = temp * cos(x * ang2rad);
  1144.                 temp = y;
  1145.                 STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].x, x, this_plot->points[i].type,
  1146.                   x_axis, NOOP, goto come_here_if_undefined);
  1147.                 STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].y, y, this_plot->points[i].type,
  1148.                   y_axis, NOOP, goto come_here_if_undefined);
  1149.             } else {    /* neither parametric or polar */
  1150.                 /* If non-para, it must be INRANGE */
  1151.                 this_plot->points[i].x = t;        /* logscale ? log(x) : x */
  1152.  
  1153.                 STORE_WITH_LOG_AND_FIXUP_RANGE(this_plot->points[i].y, temp, this_plot->points[i].type,
  1154.                                y_axis + (x_axis - y_axis) * xparam, NOOP, goto come_here_if_undefined);
  1155.  
  1156.               come_here_if_undefined:    /* could not use a continue in this case */
  1157.                 ;    /* ansi requires a statement after a label */
  1158.             }
  1159.  
  1160.             }        /* loop over samples */
  1161.             this_plot->p_count = i;    /* samples */
  1162.         }
  1163.         c_token = this_plot->token;    /* skip all modifers func / whole of data plots */
  1164.  
  1165.         tp_ptr = &(this_plot->next_cp);        /* used below */
  1166.         this_plot = this_plot->next_cp;
  1167.         }
  1168.  
  1169.         if (equals(c_token, ","))
  1170.         c_token++;
  1171.         else
  1172.         break;
  1173.     }
  1174.  
  1175.     if (parametric) {
  1176.         /* Now actually fix the plot pairs to be single plots */
  1177.         /* also fixes up polar&¶metric fn plots */
  1178.         parametric_fixup(first_plot, &plot_num);
  1179.         /* we omitted earlier check for range too small */
  1180.         fixup_range(FIRST_X_AXIS, "x");
  1181.         if (uses_axis[SECOND_X_AXIS]) {
  1182.         fixup_range(SECOND_X_AXIS, "x2");
  1183.         }
  1184.     }
  1185.     }                /* some_functions */
  1186.     /* throw out all curve_points at end of list, that we don't need  */
  1187.     cp_free(*tp_ptr);
  1188.     *tp_ptr = NULL;
  1189.  
  1190.  
  1191.     /* if first_plot is NULL, we have no functions or data at all. This can
  1192.        happen, if you type "plot x=5", since x=5 is a variable assignment */
  1193.  
  1194.     if (plot_num == 0 || first_plot == NULL) {
  1195.     int_error("no functions or data to plot", c_token);
  1196.     }
  1197.     if (uses_axis[FIRST_X_AXIS]) {
  1198.     if (max_array[FIRST_X_AXIS] == -VERYLARGE ||
  1199.         min_array[FIRST_X_AXIS] == VERYLARGE)
  1200.         int_error("all points undefined!", NO_CARET);
  1201.     FIXUP_RANGE_FOR_LOG(FIRST_X_AXIS, x);
  1202.     }
  1203.     if (uses_axis[SECOND_X_AXIS]) {
  1204.     if (max_array[SECOND_X_AXIS] == -VERYLARGE ||
  1205.         min_array[SECOND_X_AXIS] == VERYLARGE)
  1206.         int_error("all points undefined!", NO_CARET);
  1207.     FIXUP_RANGE_FOR_LOG(SECOND_X_AXIS, x2);
  1208.     } else {
  1209.     assert(uses_axis[FIRST_X_AXIS]);
  1210.     if (auto_array[SECOND_X_AXIS] & 1)
  1211.         min_array[SECOND_X_AXIS] = min_array[FIRST_X_AXIS];
  1212.     if (auto_array[SECOND_X_AXIS] & 2)
  1213.         max_array[SECOND_X_AXIS] = max_array[FIRST_X_AXIS];
  1214.     }
  1215.  
  1216.     if (!uses_axis[FIRST_X_AXIS]) {
  1217.     assert(uses_axis[SECOND_X_AXIS]);
  1218.     if (auto_array[FIRST_X_AXIS] & 1)
  1219.         min_array[FIRST_X_AXIS] = min_array[SECOND_X_AXIS];
  1220.     if (auto_array[FIRST_X_AXIS] & 2)
  1221.         max_array[FIRST_X_AXIS] = max_array[SECOND_X_AXIS];
  1222.     }
  1223.     if (uses_axis[FIRST_Y_AXIS]) {
  1224.     if (max_array[FIRST_Y_AXIS] == -VERYLARGE ||
  1225.         min_array[FIRST_Y_AXIS] == VERYLARGE)
  1226.         int_error("all points undefined!", NO_CARET);
  1227.     fixup_range(FIRST_Y_AXIS, "y");
  1228.     FIXUP_RANGE_FOR_LOG(FIRST_Y_AXIS, y);
  1229.     }                /* else we want to copy y2 range, but need to fix it up first */
  1230.     if (uses_axis[SECOND_Y_AXIS]) {
  1231.     if (max_array[SECOND_Y_AXIS] == -VERYLARGE ||
  1232.         min_array[SECOND_Y_AXIS] == VERYLARGE)
  1233.         int_error("all points undefined!", NO_CARET);
  1234.     fixup_range(SECOND_Y_AXIS, "y2");
  1235.     FIXUP_RANGE_FOR_LOG(SECOND_Y_AXIS, y2);
  1236.     } else {
  1237.     assert(uses_axis[FIRST_Y_AXIS]);
  1238.     if (auto_array[SECOND_Y_AXIS] & 1)
  1239.         min_array[SECOND_Y_AXIS] = min_array[FIRST_Y_AXIS];
  1240.     if (auto_array[SECOND_Y_AXIS] & 2)
  1241.         max_array[SECOND_Y_AXIS] = max_array[FIRST_Y_AXIS];
  1242.     }
  1243.  
  1244.     if (!uses_axis[FIRST_Y_AXIS]) {
  1245.     assert(uses_axis[SECOND_Y_AXIS]);
  1246.     if (auto_array[FIRST_Y_AXIS] & 1)
  1247.         min_array[FIRST_Y_AXIS] = min_array[SECOND_Y_AXIS];
  1248.     if (auto_array[FIRST_Y_AXIS] & 2)
  1249.         max_array[FIRST_Y_AXIS] = max_array[SECOND_Y_AXIS];
  1250.     }
  1251. #define WRITEBACK(axis,min,max) \
  1252. if(range_flags[axis]&RANGE_WRITEBACK) \
  1253.   {if (auto_array[axis]&1) min = min_array[axis]; \
  1254.    if (auto_array[axis]&2) max = max_array[axis]; \
  1255.   }
  1256.  
  1257.     WRITEBACK(FIRST_X_AXIS, xmin, xmax)
  1258.     WRITEBACK(FIRST_Y_AXIS, ymin, ymax)
  1259.     WRITEBACK(SECOND_X_AXIS, x2min, x2max)
  1260.     WRITEBACK(SECOND_Y_AXIS, y2min, y2max)
  1261.     if (strcmp(term->name, "table") == 0)
  1262.     print_table(first_plot, plot_num);
  1263.     else {
  1264.     START_LEAK_CHECK();    /* check for memory leaks in this routine */
  1265.  
  1266.     /* do_plot now uses max_array[], etc */
  1267.     do_plot(first_plot, plot_num);
  1268.  
  1269.     END_LEAK_CHECK();
  1270.     }
  1271.  
  1272.     /* if we get here, all went well, so record this line for replot */
  1273.  
  1274.     if (plot_token != -1) {
  1275.     /* note that m_capture also frees the old replot_line */
  1276.     m_capture(&replot_line, plot_token, c_token - 1);
  1277.     plot_token = -1;
  1278.     }
  1279.     cp_free(first_plot);
  1280.     first_plot = NULL;
  1281. }                /* eval_plots */
  1282.  
  1283.  
  1284.  
  1285.  
  1286. static void parametric_fixup(start_plot, plot_num)
  1287. struct curve_points *start_plot;
  1288. int *plot_num;
  1289. /*
  1290.  * The hardest part of this routine is collapsing the FUNC plot types in the
  1291.  * list (which are garanteed to occur in (x,y) pairs while preserving the
  1292.  * non-FUNC type plots intact.  This means we have to work our way through
  1293.  * various lists.  Examples (hand checked): start_plot:F1->F2->NULL ==>
  1294.  * F2->NULL start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL
  1295.  * start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL
  1296.  * 
  1297.  */
  1298. {
  1299.     struct curve_points *xp, *new_list = NULL, *free_list = NULL;
  1300.     struct curve_points **last_pointer = &new_list;
  1301.     int i, tlen, curve;
  1302.     char *new_title;
  1303.  
  1304.     /*
  1305.      * Ok, go through all the plots and move FUNC types together.  Note: this
  1306.      * originally was written to look for a NULL next pointer, but gnuplot
  1307.      * wants to be sticky in grabbing memory and the right number of items in
  1308.      * the plot list is controlled by the plot_num variable.
  1309.      * 
  1310.      * Since gnuplot wants to do this sticky business, a free_list of
  1311.      * curve_points is kept and then tagged onto the end of the plot list as
  1312.      * this seems more in the spirit of the original memory behavior than
  1313.      * simply freeing the memory.  I'm personally not convinced this sort of
  1314.      * concern is worth it since the time spent computing points seems to
  1315.      * dominate any garbage collecting that might be saved here...
  1316.      */
  1317.     new_list = xp = start_plot;
  1318.     curve = 0;
  1319.  
  1320.     while (++curve <= *plot_num) {
  1321.     if (xp->plot_type == FUNC) {
  1322.         /* Here's a FUNC parametric function defined as two parts. */
  1323.         struct curve_points *yp = xp->next_cp;
  1324.  
  1325.         --(*plot_num);
  1326.  
  1327.         assert(xp->p_count == yp->p_count);
  1328.  
  1329.         /* because syntax is   plot x(t), y(t) axes ..., only
  1330.          * the y function axes are correct
  1331.          */
  1332.  
  1333.  
  1334.         /*
  1335.          * Go through all the points assigning the y's from xp to be the x's
  1336.          * for yp. In polar mode, we need to check max's and min's as we go.
  1337.          */
  1338.  
  1339.         for (i = 0; i < yp->p_count; ++i) {
  1340.         if (polar) {
  1341.             double r = yp->points[i].y;
  1342.             double t = xp->points[i].y * ang2rad;
  1343.             double x, y;
  1344.             if (!(autoscale_r & 2) && r > rmax)
  1345.             yp->points[i].type = OUTRANGE;
  1346.             if (!(autoscale_r & 1))
  1347.             r -= rmin;    /* store internally as if plotting r(t)-rmin */
  1348.             x = r * cos(t);
  1349.             y = r * sin(t);
  1350.             /* we hadn't done logs when we stored earlier */
  1351.             STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].x, x, yp->points[i].type,
  1352.                          xp->x_axis, NOOP, NOOP);
  1353.             STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].y, y, yp->points[i].type,
  1354.                          xp->y_axis, NOOP, NOOP);
  1355.         } else {
  1356.             double x = xp->points[i].y;
  1357.             double y = yp->points[i].y;
  1358.             STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].x, x,
  1359.                  yp->points[i].type, yp->x_axis, NOOP, NOOP);
  1360.             STORE_WITH_LOG_AND_FIXUP_RANGE(yp->points[i].y, y,
  1361.                  yp->points[i].type, yp->y_axis, NOOP, NOOP);
  1362.         }
  1363.         }
  1364.  
  1365.         /* Ok, fix up the title to include both the xp and yp plots. */
  1366.         if (xp->title && xp->title[0] != '\0' && yp->title) {
  1367.         tlen = strlen(yp->title) + strlen(xp->title) + 3;
  1368.         new_title = gp_alloc((unsigned long) tlen, "string");
  1369.         strcpy(new_title, xp->title);
  1370.         strcat(new_title, ", ");    /* + 2 */
  1371.         strcat(new_title, yp->title);    /* + 1 = + 3 */
  1372.         free(yp->title);
  1373.         yp->title = new_title;
  1374.         }
  1375.         /* move xp to head of free list */
  1376.         xp->next_cp = free_list;
  1377.         free_list = xp;
  1378.  
  1379.         /* append yp to new_list */
  1380.         *last_pointer = yp;
  1381.         last_pointer = &(yp->next_cp);
  1382.         xp = yp->next_cp;
  1383.  
  1384.     } else {        /* data plot */
  1385.         assert(*last_pointer == xp);
  1386.         last_pointer = &(xp->next_cp);
  1387.         xp = xp->next_cp;
  1388.     }
  1389.     }                /* loop over plots */
  1390.  
  1391.     first_plot = new_list;
  1392.  
  1393.     /* Ok, stick the free list at the end of the curve_points plot list. */
  1394.     *last_pointer = free_list;
  1395. }
  1396.